package org.flashIso.engine.objects {
	import com.adobe.serialization.json.JSON;
	
	import flash.events.Event;
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;
	
	import org.flashIso.engine.core.FillDescriptor;
	import org.flashIso.engine.core.ILibrary;
	import org.flashIso.engine.core.ISerializableXML;
	import org.flashIso.engine.core.IsoObjectBase;
	import org.flashIso.engine.core.Point2D;
	import org.flashIso.engine.core.Point3D;
	import org.flashIso.engine.events.IsoEvent;
	import org.flashIso.engine.library.objects.LTile;
	
	/**
	 * @author Marius Dorin Moraru
	 */
	public class IsoTile extends IsoObjectBase implements ISerializableXML{
		private var _cell : Point2D = new Point2D();
		private var _fillColor : uint = 0x000000;
		private var _fillAlpha : Number = 0.2;
		private var _lineThickness : uint = 1;
		private var _lineColor : uint = 0.000000;
		private var _lineAlpha : Number = 0.5;
		private var _elevationNorth : Number = 0;
		private var _elevationSouth : Number = 0;
		private var _elevationEast : Number = 0;
		private var _elevationWest : Number = 0;
		private var _walkable : Boolean = true;
		private var _selected : Boolean = true;
		
		protected var _libraryReference : LTile;
		
		public function IsoTile() {
			super();
			size = new Point3D(50, 50, 0);			
			size.addEventListener(Event.CHANGE, triggerValidation, false, 0, true);			
			cell.addEventListener(Event.CHANGE, cellChangeHandler, false, 0, true);			
			delta = new Point3D(-50, -50)
		}
		
		/**
		 * Iso cell
		 **/
		public function get cell() : Point2D {
			return _cell;
		}
		
		public function set cell(point2D : Point2D) : void {
			if (!_cell.equals(point2D)){
				_cell.x = Math.floor(point2D.x);
				_cell.y = Math.floor(point2D.y);
			}
		}
		
		protected function cellChangeHandler(e:Event) : void {
			dispatchEvent(new IsoEvent(IsoEvent.CELL_CHANGE));
		}
		
		/**
		 * Tile faces color
		 **/
		public function set fillColor(value : uint) : void {
			if (_fillColor != value) {
				_fillColor = value;
				triggerValidation();
			}
		}
		public function get fillColor() : uint {
			return _fillColor;
		}
		
		
		/**
		 * Tile faces alpha
		 **/
		public function set fillAlpha(value : Number) : void {
			if (_fillAlpha != value) {
				_fillAlpha = value;
				triggerValidation();
			}
		}
		public function get fillAlpha() : Number {
			return _fillAlpha;
		}

		/**
		 * Tile wireframe thickness
		 **/
		public function set lineThickness(value : uint) : void {
			if (_lineThickness != value) {
				_lineThickness = value;
				triggerValidation();
			}
		}
		public function get lineThickness() : uint {
			return _lineThickness;
		}
		
		/**
		 * Tile wireframe color
		 **/
		public function set lineColor(value : uint) : void {
			if (_lineColor != value) {
				_lineColor = value;
				triggerValidation();
			}
		}
		
		public function get lineColor() : uint {
			return _lineColor;
		}
		
		
		/**
		 * Tile wireframe alpha
		 **/
		public function set lineAlpha(value : Number) : void {
			if (_lineAlpha != value) {
				_lineAlpha = value;
				triggerValidation();
			}
		}
		
		public function get lineAlpha() : Number {
			return _lineAlpha;
		}
		
		
		/**
		 * Flag indicating if the tile is walkable
		 * It does not affect the shape or the image in any way.
		 * 
		 **/
		public function set walkable(value : Boolean) : void {
			if (_walkable != value) {
				_walkable = value;
				triggerValidation();
			}
		}
		public function get walkable() : Boolean {
			return _walkable;
		}
		
		
		override public function validateNow() : void {
			fills.autoValidation = false;
			
			fills.removeAll();
			if (drawShape){
				if ( (size.z + _elevationEast != 0) || (size.z + elevationSouth != 0)){
					var fill : FillDescriptor = new FillDescriptor();
					fill.autoValidation = false;
					fill.color = _fillColor;
					fill.alpha = _fillAlpha;
					fill.lineThickness = _lineThickness;
					fill.lineColor = _lineColor;
					fill.lineAlpha = _lineAlpha;
					fill.autoValidation = true;
					fill.pointsList.autoValidation = false;
					fill.pointsList.add(new Point3D(0, 0, 0));
					fill.pointsList.add(new Point3D(size.x, 0, 0));
					fill.pointsList.add(new Point3D(size.x, 0, size.z + _elevationEast));
					fill.pointsList.add(new Point3D(0, 0, size.z + elevationSouth));
					fill.pointsList.autoValidation = true;
					fills.add(fill);
				}
				
				if ( (size.z + _elevationWest != 0) || (size.z + elevationSouth != 0)){
					fill = new FillDescriptor();
					fill.autoValidation = false;
					fill.color = _fillColor;
					fill.alpha = _fillAlpha;
					fill.lineThickness = _lineThickness;
					fill.lineColor = _lineColor;
					fill.lineAlpha = _lineAlpha;
					fill.autoValidation = true;
					fill.pointsList.autoValidation = false;
					fill.pointsList.add(new Point3D(0, 0, 0));
					fill.pointsList.add(new Point3D(0, size.y, 0));
					fill.pointsList.add(new Point3D(0, size.y, size.z + _elevationWest));
					fill.pointsList.add(new Point3D(0, 0, size.z + _elevationSouth));
					fill.pointsList.autoValidation = true;
					fills.add(fill);
				}
				
				fill = new FillDescriptor();
				fill.autoValidation = false;
				fill.color = _fillColor;
				fill.alpha = _fillAlpha;
				fill.lineThickness = _lineThickness;
				fill.lineColor = _lineColor;
				fill.lineAlpha = _lineAlpha;
				fill.autoValidation = true;
				fill.pointsList.autoValidation = false;
				fill.pointsList.add(new Point3D(0, 0, size.z + _elevationSouth));
				fill.pointsList.add(new Point3D(size.x, 0, size.z + _elevationEast));
				fill.pointsList.add(new Point3D(size.x, size.y, size.z + _elevationNorth));
				fill.pointsList.add(new Point3D(0, size.y, size.z + _elevationWest));
				fill.pointsList.autoValidation = true;
				fills.add(fill);
				
				fills.autoValidation = true;
			}
			//addToChangeQue();
			super.validateNow();
		}
		
		
		public function set elevationNorth(value : Number) : void {
			if (_elevationNorth != value) {
				_elevationNorth = value;
				triggerValidation();
			}
		}
		
		public function get elevationNorth() : Number {
			return _elevationNorth;
		}
		
		public function set elevationSouth(value : Number) : void {
			if (_elevationSouth != value) {
				_elevationSouth = value;
				triggerValidation();
			}
		}
		
		public function get elevationSouth() : Number {
			return _elevationSouth;
		}
		
		public function set elevationEast(value : Number) : void {
			if (_elevationEast != value) {
				_elevationEast = value;
				triggerValidation();
			}
		}
		
		public function get elevationEast() : Number {
			return _elevationEast;
		}
		
		public function set elevationWest(value : Number) : void {
			if (_elevationWest != value) {
				_elevationWest = value;
				triggerValidation();
			}
		}
		
		public function get elevationWest() : Number {
			return _elevationWest;
		}
		
		/**
		 * Set elevationNorth and elevationSouth and elevationEast and elevationWest.
		 **/
		public function set elevation(value : Number) : void {
			if (value != elevation) {
				_elevationWest = _elevationSouth = _elevationEast = _elevationNorth = value;
				triggerValidation();
			}
		}
		
		
		/**
		 * Returns the average of elevationNorth and elevationSouth and elevationEast and elevationWest.  
		 **/
		public function get elevation() : Number {
			return (_elevationEast + _elevationNorth + _elevationSouth + _elevationWest) * 0.25;
		}
		
		public function set libraryReference(value:LTile) : void {
			if (_libraryReference != value){
				if (_libraryReference != null){
					_libraryReference.removeEventListener(Event.CHANGE, referenceChange);
				}
				_libraryReference = value;
				if (_libraryReference != null){
					_libraryReference.addEventListener(Event.CHANGE, referenceChange, false, 0, true);
				}
				referenceChange(null);
			}
		}
		
		public function get libraryReference() : LTile {
			return _libraryReference;
		}
		
		protected function referenceChange(e:Event) : void {
			this.fillColor = _libraryReference.fillColor;
			this.fillAlpha = _libraryReference.fillAlpha;
			this.lineThickness = _libraryReference.lineThickness;
			this.lineColor = _libraryReference.lineColor;
			this.lineAlpha = _libraryReference.lineAlpha;
			
			this.delta.x = _libraryReference.deltaX;
			this.delta.y = _libraryReference.deltaY;
			this.delta.z = _libraryReference.deltaZ;
			
			this.size.x = _libraryReference.xSize;
			this.size.y = _libraryReference.ySize;
			this.size.z = _libraryReference.zSize;
			
			this.elevationNorth = _libraryReference.elevationNorth;
			this.elevationSouth = _libraryReference.elevationSouth;
			this.elevationEast = _libraryReference.elevationEast;
			this.elevationWest = _libraryReference.elevationWest;
			this.useImageFramesWhenRotating = _libraryReference.useImageFramesWhenRotating;
			this.image.libraryReference = _libraryReference.image;
			
			this.image.x = _libraryReference.imageX;
			this.image.y = _libraryReference.imageY;
			this.image.scaleX = _libraryReference.imageScaleX;
			this.image.scaleY = _libraryReference.imageScaleY;
			this.image.rotation = _libraryReference.imageRotation;
			this.image.alpha = _libraryReference.imageAlpha;
			this.drawShape = _libraryReference.drawShape;
			this.hitAreaType = _libraryReference.hitAreaType;
		}
		public function toXML() : XML {
			var xml:XML = new XML("<" + className + "  />");
			xml.@cellX = cell.x;
			xml.@cellY = cell.y;
			
			xml.@walkable = walkable;
			xml.@imageFrame = image.frame;
			
			xml.@rotation = rotation;
			xml.@alpha = alpha;
			if (libraryReference != null) {
				xml.@libraryID = libraryReference.id;
			}
			xml.@name = name;
			
			xml.@customProperties = JSON.encode(customProperties);
//			if (image != null) {
//				xml.appendChild(image.toXML());
//			}
			return xml;
		}
		
		public function fromXML(xml:XML, library:ILibrary = null) : void {
			
			if (library != null){
				libraryReference = library.getLTileByID(xml.@libraryID + "");
			}

			cell.x = parseFloat(xml.@cellX);
			cell.y = parseFloat(xml.@cellY);
			
			walkable = ((xml.@walkable+"").toLowerCase() == "true");
			image.frame = (xml.@imageFrame + "");
			
			rotation = parseFloat(xml.@rotation);
			alpha = parseFloat(xml.@alpha);
			
			name = (xml.@name + "");
			customProperties = JSON.decode(xml.@customProperties + "");
		}
	}
}
